Introduction

1. Data Description

1.1. Sample Selected

You can define bullet list or numbered list:

  • Pizza
  • Pasta
  • Cafe
    • Espresso
    • Macchiato
    • Cappuccino
  • Vodka
    • Bisont Grass
    • Soplica

1.2. Formula

Here you can define formula

\[ y = \beta_0 + \beta_1X + \epsilon \] the formula can be reported in the text: \(\mu = 1/n \sum X_i\)

1.3. Import Data (CSV) [*]

data_SD3 <- read.delim("~/RProjects/2024-Q2-R-2 [MDA2024, exercises]/D1_SD3/data_SD3.csv", stringsAsFactors=TRUE)

2. Data Analysis

To add R code in the Notebook we need to use the Chunk.

X <- iris

It is possible to have an overview of the data by using the summary function.

summary(X)
  Sepal.Length    Sepal.Width     Petal.Length  
 Min.   :4.300   Min.   :2.000   Min.   :1.000  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600  
 Median :5.800   Median :3.000   Median :4.350  
 Mean   :5.843   Mean   :3.057   Mean   :3.758  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100  
 Max.   :7.900   Max.   :4.400   Max.   :6.900  
  Petal.Width          Species  
 Min.   :0.100   setosa    :50  
 1st Qu.:0.300   versicolor:50  
 Median :1.300   virginica :50  
 Mean   :1.199                  
 3rd Qu.:1.800                  
 Max.   :2.500                  

In R there are three main type of data:

Y <- as.matrix(X[ ,1:4])

To handle data you can use the following code:

X[10, 2]       # selection of one element in the Data Frame (or matrix)
[1] 3.1
X[5:20, 1:3]   # selection of an interval
X[5:20, ]      # the empty space select all the columns or rows
X$Sepal.Length # the symbol $ is used to select a column in the data frame
  [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8
 [14] 4.3 5.8 5.7 5.4 5.1 5.7 5.1 5.4 5.1 4.6 5.1 4.8 5.0
 [27] 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5 4.9 5.0 5.5 4.9 4.4
 [40] 5.1 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0 6.4
 [53] 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 5.0 5.9 6.0 6.1 5.6
 [66] 6.7 5.6 5.8 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7
 [79] 6.0 5.7 5.5 5.5 5.8 6.0 5.4 6.0 6.7 6.3 5.6 5.5 5.5
 [92] 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7 6.3 5.8 7.1 6.3
[105] 6.5 7.6 4.9 7.3 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5
[118] 7.7 7.7 6.0 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2
[131] 7.4 7.9 6.4 6.3 6.1 7.7 6.3 6.4 6.0 6.9 6.7 6.9 5.8
[144] 6.8 6.7 6.7 6.3 6.5 6.2 5.9

2.1. Plots in R

boxplot(X$Sepal.Length, main = "Box Plot of the Sepal Length of the IRIS Flowers", col = "blue", horizontal = T)
Error in if (horizontal) plot.window(ylim = xlim, xlim = ylim, log = log,  : 
  the condition has length > 1

The elements of the box-plot are reported below:

# just a boxplot
boxplot(X[ ,1:4])

# boxplot with a title and colors
boxplot(X[ ,1:4], main = "Box Plot of all quantitative variables of IRIS data", col = terrain.colors(4))

boxplot(X$Sepal.Width ~ X$Species, main = "Box Plot of Sepal Width considering the 3 types of flowers", xlab = "Type of IRIS Flowers", ylab = "Sepal Width", col = terrain.colors(4))

The tilde symbol is obtained by:

[ 2.1. BONUS ]

The bold line is the Median, that is the value of the ordered distribution that leaves the same number of units above and below (or on left and right)

  • Q1 is the first quartile. Q1 leaves 25% of unirs on left and 75% on right.
  • Q3 is the third quartile. Q3 leaves 75% of units on left and 25% on right.
  • Wishers, without outliers are, the min and max of distribution
  • Wishers, with outliers are, Lmin = Q1-1.5(Q3-Q1); Lsup = Q3+1.5(Q3-Q1);
boxplot(X$Sepal.Length, main = "Box-Plot of the Sepal Lenght", col = "green", horizontal = F)

boxplot(X[ ,1:4], main = "Box-Plot with all the Variables", col = "blue", horizontal = F)

boxplot(X$Sepal.Width ~ X$Species, main = "Box-Plot about Sepal Width with different type of IRIS Flowers")

2.2. Bar Plot

Bar Plot can be used for Qualitative Data and for Categorized Quantitative Data. The first step to create a Bar Plot is to generate a Table of Frequency.

T <- table(X$Species)
T

    setosa versicolor  virginica 
        50         50         50 
barplot(T, main = "Bar Plot of Type of flowers", xlab = "Type of flowers", ylab = "Absolute Frequency", col = terrain.colors(4))

2.3. Pie Chart

It is based on the frequency table.

pie(T, main = "Pie Chart", col = terrain.colors(4))

2.4. Histogram Chart

Histogram is a plot used only for Quantitative Data, it is based on a frequency tables in classes. The R function is called hist and the input is a simple distribution of a quantitative variable.

hist(X$Sepal.Length)

hist(X$Sepal.Width, main = "Histogram of Sepal Width", xlab = "Classes", ylab = "Absolute Frequency", col = "lightgreen", border = "blue")

[ 2.4. BONUS ]

he histogram can be used only for quantitative variables.

hist(X$Sepal.Width, main = "Histogram of the Sepal Width", xlab = "Classes",
     ylab = "Absolute Frequency", col = "green", border = "red", breaks = 10)

In case of equally spaced (same size) classes we can report on the Y axis the Absolute Frequency or relative frequency. In case of classes with different sizes we have to report on Y axis the density of frequency. The formula is the following: \(d_i = n_i/h_i\), where \(n_i\) is the absolute frequency and \(h_i\) is the size of the class.

3. Correlation Analysis

3.1. Correlation Plot

plot(X$Sepal.Length, X$Sepal.Width, main = "Correlation Plot", xlab = "Sepal Length", ylab = "Sepal Width")

[ 3.1. BONUS ]

plot(X$Petal.Length, X$Petal.Width, main = "Correlation Plot",
     xlab = "Petal Lenght", ylab = "Petal Width", col = "blue",
     pch = 1)

Plots with IRIS

plot(X$Sepal.Length, X$Sepal.Width, main = "(1-2) Plot with IRIS", 
     xlab = "Sepal Lenght", ylab = "Sepal Width", col = "blue")

plot(X$Petal.Length, X$Petal.Width, main = "(2-2) Plot with IRIS", 
     xlab = "Petal Lenght", ylab = "Petal Width", col = "red")

3.2. Pair Plot

pairs(X[ ,1:4])

The plots below the main diagonal are the same of the plot above the main diagonal. The reason is because the plot and the correlation index are symmetric.

r <- cor(X[ ,1:2])
r <- round(r, 3)
r
             Sepal.Length Sepal.Width
Sepal.Length        1.000      -0.118
Sepal.Width        -0.118       1.000
cor(X$Sepal.Length, X$Sepal.Width)
[1] -0.1175698

The range of correlation index is: -1 <= r <= 1 The interpretation of the Correlation Index called r is following:

  • 0.00 < |r| <= 0.25 Low Correlation
  • 0.25 < |r| <= 0.50 Medium-Low Correlation
  • 0.50 < |r| <= 0.75 Medium-High Correlation
  • 0.75 < |r| <= 1.00 High Correlation
  • 0 No Correlation
  • 1 Perfect Correlation

The correlation between Sepal Length and Sepal Width is -0.118 and it is a low negative correlation.

4. Plots with GGPLOT Package

install.packages("ggplot2")
Error in install.packages : Updating loaded packages
library(ggplot2)

GGPLOTS has 3 main arguments:

# GGPLOT (example no 1)
ggplot(data = X[ ,1:2])

# GGPLOT (example no 2.1)
ggplot(data = X[ ,1:2]) +
  geom_point(mapping = aes(X$Sepal.Length, X$Sepal.Width))

# GGPLOT (example no 2.2)
ggplot(data = X[ ,1:2]) +
  geom_point(mapping = aes(Sepal.Length, Sepal.Width))

# GGPLOT (example no 2.2)
ggplot(data = X) +
  geom_point(mapping = aes(Sepal.Length, Sepal.Width))

# GGPLOT (example no 3)
ggplot(data = X) +
  geom_point(mapping = aes(Sepal.Length, Sepal.Width)) +
  ggtitle("Scatter Plot") + xlab("Sepal Length") + ylab("Sepal Width")

4.1. Correlation Plot (Scatter Plot) with colors

ggplot(data = X) +
  geom_point(mapping = aes(Sepal.Length, Sepal.Width, color = Species))

[ 4.1. BONUS ]

STANDARD TEMPLATE IS: ggplot(data = ) + (mapping = aes())

# First Example
ggplot(data = X) + 
  geom_point(mapping = aes(Petal.Length, Petal.Width, color = Species)) +
  ggtitle("Petal Lenght and Width") +
  xlab("Petal Lenght") + ylab("Petal Width")

# Second Example
ggplot(data = X, mapping = aes(Petal.Width, Petal.Length)) + 
  geom_point(mapping = aes(color = Species)) +
  ggtitle("Petal Width and Lenght") + 
  xlab("Petal Width") + ylab("Petal Lenght")

4.2. Box Plot

ggplot(data = X) +
  geom_boxplot(mapping = aes(Sepal.Width), color = "blue", outlier.colour = "red", outlier.shape = 8, outlier.size = 3) +
  ggtitle("Box Plot for Sepal Lenght")

Box Plot taking into account the 3 types of flowers

ggplot(data = X) +
  geom_boxplot(mapping = aes(Species, Sepal.Width), outlier.color = "red", outlier.shape = 8)

GGPLOT function as object

p <- ggplot(data = X) +
  geom_boxplot(mapping = aes(Species, Sepal.Width, fill = Species))
p

p + theme(legend.position = "bottom")

4.3. Bar Plot

ggplot(data = X) + 
  geom_bar(mapping = aes(Species)) + 
  ggtitle("Bar Plot with GGPLOT") + 
  ylab("Absolute Frequency")

6. Regression Model [*]

In regression model we need to define the dependent and independent variables. In our case the model is define as follow:

In the first place we need to create a scatter plot (correlation plot).

6.1. Regression Model: Plot [*]

ggplot(data = Y) +
  geom_point(mapping = aes(displ, hwy)) +
  geom_smooth(method = lm, mapping = aes(displ, hwy))
`geom_smooth()` using formula = 'y ~ x'

6.2. Regression Model: Different Plot per each group [*]

ggplot(data = Y) +
  geom_point(mapping = aes(displ, hwy, color  = drv)) +
  geom_smooth(method = lm, mapping = aes(displ, hwy, color = drv))
`geom_smooth()` using formula = 'y ~ x'

6.3. Regression Model: Parameters Estimation [*]

res.reg <- lm(hwy ~ displ, data = Y)
summary(res.reg)

Call:
lm(formula = hwy ~ displ, data = Y)

Residuals:
    Min      1Q  Median      3Q     Max 
-7.1039 -2.1646 -0.2242  2.0589 15.0105 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  35.6977     0.7204   49.55   <2e-16 ***
displ        -3.5306     0.1945  -18.15   <2e-16 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.836 on 232 degrees of freedom
Multiple R-squared:  0.5868,    Adjusted R-squared:  0.585 
F-statistic: 329.5 on 1 and 232 DF,  p-value: < 2.2e-16
LS0tCnRpdGxlOiAiTXkgRmlyc3QgTm90ZWJvb2sgTURBMjAyNCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBJbnRyb2R1Y3Rpb24KCgojIDEuIERhdGEgRGVzY3JpcHRpb24KCiMjIDEuMS4gU2FtcGxlIFNlbGVjdGVkCgpZb3UgY2FuIGRlZmluZSBidWxsZXQgbGlzdCBvciBudW1iZXJlZCBsaXN0OgoKLSBQaXp6YQotIFBhc3RhCi0gQ2FmZQogIC0gRXNwcmVzc28KICAtIE1hY2NoaWF0bwogIC0gQ2FwcHVjY2lubwotIFZvZGthCiAgLSBCaXNvbnQgR3Jhc3MKICAtIFNvcGxpY2EKCiMjIDEuMi4gRm9ybXVsYQoKSGVyZSB5b3UgY2FuIGRlZmluZSBmb3JtdWxhCgokJCB5ID0gXGJldGFfMCArIFxiZXRhXzFYICsgXGVwc2lsb24gJCQKdGhlIGZvcm11bGEgY2FuIGJlIHJlcG9ydGVkIGluIHRoZSB0ZXh0OiAkXG11ID0gMS9uIFxzdW0gWF9pJAoKIyMgMS4zLiBJbXBvcnQgRGF0YSAoQ1NWKSBbKl0KCmBgYHtyfQpkYXRhX1NEMyA8LSByZWFkLmRlbGltKCJ+L1JQcm9qZWN0cy8yMDI0LVEyLVItMiBbTURBMjAyNCwgZXhlcmNpc2VzXS9EMV9TRDMvZGF0YV9TRDMuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycz1UUlVFKQpgYGAKCiMgMi4gRGF0YSBBbmFseXNpcwpUbyBhZGQgUiBjb2RlIGluIHRoZSBOb3RlYm9vayB3ZSBuZWVkIHRvIHVzZSB0aGUgKipDaHVuayoqLgoKYGBge3J9ClggPC0gaXJpcwpgYGAKCkl0IGlzIHBvc3NpYmxlIHRvIGhhdmUgYW4gb3ZlcnZpZXcgb2YgdGhlIGRhdGEgYnkgdXNpbmcgdGhlICpzdW1tYXJ5KiBmdW5jdGlvbi4KCmBgYHtyfQpzdW1tYXJ5KFgpCmBgYApJbiBSIHRoZXJlIGFyZSB0aHJlZSBtYWluIHR5cGUgb2YgZGF0YToKCi0gKipNYXRyaXgqKi4gTWF0aGVtYXRpY2FsIE9iamVjdC4gSW4gb3VyIGV4YW1wbGUgKipZKiogaXMgYSBtYXRyaXguCi0gKipEYXRhIEZyYW1lKiouIEl0IGlzIGRldm90ZWQgdG8gb3JnYW5pemUgYW5kIGFuYWx5emUgZGF0YSBhbmQgaXQgaXMgYSBnZW5lcmFsaXphdGlvbiBvZiB0aGUgTWF0cml4LiBJbiBvdXIgZXhhbXBsZSwgKipYKiogaXMgYSBkYXRhIGZyYW1lLgotICoqTGlzdCoqLiBJdCBpcyBhbiBvYmplY3QgdGhhdCBjYW4gaW5jbHVkZSBEYXRhIEZyYW1lcywgTWF0cmljZXMgb3Igb3RoZXIgbGlzdHMuCgpgYGB7cn0KWSA8LSBhcy5tYXRyaXgoWFsgLDE6NF0pCmBgYAoKVG8gaGFuZGxlIGRhdGEgeW91IGNhbiB1c2UgdGhlIGZvbGxvd2luZyBjb2RlOgoKYGBge3J9ClhbMTAsIDJdICAgICAgICMgc2VsZWN0aW9uIG9mIG9uZSBlbGVtZW50IGluIHRoZSBEYXRhIEZyYW1lIChvciBtYXRyaXgpClhbNToyMCwgMTozXSAgICMgc2VsZWN0aW9uIG9mIGFuIGludGVydmFsClhbNToyMCwgXSAgICAgICMgdGhlIGVtcHR5IHNwYWNlIHNlbGVjdCBhbGwgdGhlIGNvbHVtbnMgb3Igcm93cwpYJFNlcGFsLkxlbmd0aCAjIHRoZSBzeW1ib2wgJCBpcyB1c2VkIHRvIHNlbGVjdCBhIGNvbHVtbiBpbiB0aGUgZGF0YSBmcmFtZQpgYGAKIyAyLjEuIFBsb3RzIGluIFIKCmBgYHtyfQpib3hwbG90KFgkU2VwYWwuTGVuZ3RoLCBtYWluID0gIkJveCBQbG90IG9mIHRoZSBTZXBhbCBMZW5ndGggb2YgdGhlIElSSVMgRmxvd2VycyIsIGNvbCA9ICJibHVlIiwgaG9yaXpvbnRhbCA9IFQpCmBgYApUaGUgZWxlbWVudHMgb2YgdGhlIGJveC1wbG90IGFyZSByZXBvcnRlZCBiZWxvdzoKCi0gKipRMSoqLiBJdCBpcyB0aGUgKkZpcnN0IFF1YXJ0aWxlKi4gSXQgbGVhdmVzIDI1JSBvZiB1bml0cyBvbiB0aGUgbGVmdCBhbmQgNzUlIG9mIHVuaXRzIG9uIHRoZSByaWdodC4gKkxlZnQgc2lkZSBvZiB0aGUgYm94KgotICoqTWUqKi4gSXQgaXMgdGhlICpNZWRpYW49UTIqLiBJdCBsZWF2ZXMgNTAlIG9mIHVuaXRzIG9uIGxlZnQgYW5kIHJpZ2h0LiAqQm9sZCBMaW5lIGluIHRoZSBtaWRkbGUgb2YgdGhlIGJveCoKLSAqKlEzKiouIEl0IGlzIHRoZSAqVGhpcmQgUXVhcnRpbGUqLiBJdCBsZWF2ZXMgNzUlIG9mIHRoZSB1bml0cyBvbiB0aGUgbGVmdCBhbmQgMjUlIG9mIHRoZSB1bml0cyBvbiB0aGUgcmlnaHQuICpSaWdodCBzaWRlIG9mIHRoZSBib3gqCi0gSW4gY2FzZSBvZiAqKm5vIG91dGxpZXJzKiosIHRoZSB3aGlza2VycyBhcmUgZGVmaW5lZCBhczoKICAtICoqWG1pbioqIGlzIHRoZSBsZWZ0IHdoaXNrZXJzCiAgLSAqKlhtYXgqKiBpcyB0aGUgcmlnaHQgd2hpc2tlcnMKLSBJbiBjYXNlIG9mICoqb3V0bGllcnMqKiwgdGhlIHdoaXNrZXJzIGFyZSBkZWZpbmVkIGFzOgogIC0gKipMaW5mKiogPSBRMSAtIDEuNSAoUTMtUTEpOiBMb3dlciBMaW1pdAogIC0gKipMc3VwKiogPSBRMSArIDEuNSAoUTMtUTEpOiBVcHBlciBMaW1pdAogIApgYGB7cn0KIyBqdXN0IGEgYm94cGxvdApib3hwbG90KFhbICwxOjRdKQojIGJveHBsb3Qgd2l0aCBhIHRpdGxlIGFuZCBjb2xvcnMKYm94cGxvdChYWyAsMTo0XSwgbWFpbiA9ICJCb3ggUGxvdCBvZiBhbGwgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyBvZiBJUklTIGRhdGEiLCBjb2wgPSB0ZXJyYWluLmNvbG9ycyg0KSkKYGBgCiAgCmBgYHtyfQpib3hwbG90KFgkU2VwYWwuV2lkdGggfiBYJFNwZWNpZXMsIG1haW4gPSAiQm94IFBsb3Qgb2YgU2VwYWwgV2lkdGggY29uc2lkZXJpbmcgdGhlIDMgdHlwZXMgb2YgZmxvd2VycyIsIHhsYWIgPSAiVHlwZSBvZiBJUklTIEZsb3dlcnMiLCB5bGFiID0gIlNlcGFsIFdpZHRoIiwgY29sID0gdGVycmFpbi5jb2xvcnMoNCkpCmBgYAoKVGhlICp0aWxkZSBzeW1ib2wqIGlzIG9idGFpbmVkIGJ5OgoKLSB0aGVzZSBkb2Vzbid0IHdvcmsgWypdOgogIC0gTUFDOiBvcHRpb24gKyA1CiAgLSBXSU46IEFMVCArIDEyNS82Ci0gdGhlc2Ugd29ya3MgWypdOgogIC0gTUFDOiBzaGlmdCArIGJ1dHRvbiBiZWZvcmUgbm8uMQogIC0gV0lOOiBzaGlmdCArIGJ1dHRvbiBiZWZvcmUgbm8uMQoKIyMgWyAyLjEuIEJPTlVTIF0KClRoZSBib2xkIGxpbmUgaXMgdGhlICoqTWVkaWFuKiosIHRoYXQgaXMgdGhlIHZhbHVlIG9mIHRoZSBvcmRlcmVkIGRpc3RyaWJ1dGlvbiB0aGF0IGxlYXZlcyB0aGUgc2FtZSBudW1iZXIgb2YgdW5pdHMgYWJvdmUgYW5kIGJlbG93IChvciBvbiBsZWZ0IGFuZCByaWdodCkKCi0gKipRMSoqIGlzIHRoZSBmaXJzdCBxdWFydGlsZS4gUTEgbGVhdmVzIDI1JSBvZiB1bmlycyBvbiBsZWZ0IGFuZCA3NSUgb24gcmlnaHQuCi0gKipRMyoqIGlzIHRoZSB0aGlyZCBxdWFydGlsZS4gUTMgbGVhdmVzIDc1JSBvZiB1bml0cyBvbiBsZWZ0IGFuZCAyNSUgb24gcmlnaHQuCi0gV2lzaGVycywgKip3aXRob3V0IG91dGxpZXJzKiogYXJlLCB0aGUgbWluIGFuZCBtYXggb2YgZGlzdHJpYnV0aW9uCi0gV2lzaGVycywgKip3aXRoIG91dGxpZXJzKiogYXJlLCBMbWluID0gUTEtMS41KihRMy1RMSk7IExzdXAgPSBRMysxLjUqKFEzLVExKTsKCmBgYHtyfQpib3hwbG90KFgkU2VwYWwuTGVuZ3RoLCBtYWluID0gIkJveC1QbG90IG9mIHRoZSBTZXBhbCBMZW5naHQiLCBjb2wgPSAiZ3JlZW4iLCBob3Jpem9udGFsID0gRikKYm94cGxvdChYWyAsMTo0XSwgbWFpbiA9ICJCb3gtUGxvdCB3aXRoIGFsbCB0aGUgVmFyaWFibGVzIiwgY29sID0gImJsdWUiLCBob3Jpem9udGFsID0gRikKYm94cGxvdChYJFNlcGFsLldpZHRoIH4gWCRTcGVjaWVzLCBtYWluID0gIkJveC1QbG90IGFib3V0IFNlcGFsIFdpZHRoIHdpdGggZGlmZmVyZW50IHR5cGUgb2YgSVJJUyBGbG93ZXJzIikKYGBgCgojIDIuMi4gQmFyIFBsb3QKCkJhciBQbG90IGNhbiBiZSB1c2VkIGZvciAqKlF1YWxpdGF0aXZlIERhdGEqKiBhbmQgZm9yICoqQ2F0ZWdvcml6ZWQgUXVhbnRpdGF0aXZlIERhdGEqKi4gVGhlIGZpcnN0IHN0ZXAgdG8gY3JlYXRlIGEgQmFyIFBsb3QgaXMgdG8gZ2VuZXJhdGUgYSAqVGFibGUgb2YgRnJlcXVlbmN5Ki4KCmBgYHtyfQpUIDwtIHRhYmxlKFgkU3BlY2llcykKVApgYGAKCmBgYHtyfQpiYXJwbG90KFQsIG1haW4gPSAiQmFyIFBsb3Qgb2YgVHlwZSBvZiBmbG93ZXJzIiwgeGxhYiA9ICJUeXBlIG9mIGZsb3dlcnMiLCB5bGFiID0gIkFic29sdXRlIEZyZXF1ZW5jeSIsIGNvbCA9IHRlcnJhaW4uY29sb3JzKDQpKQpgYGAKCiMgMi4zLiBQaWUgQ2hhcnQKCkl0IGlzIGJhc2VkIG9uIHRoZSBmcmVxdWVuY3kgdGFibGUuCgpgYGB7cn0KcGllKFQsIG1haW4gPSAiUGllIENoYXJ0IiwgY29sID0gdGVycmFpbi5jb2xvcnMoNCkpCmBgYAoKIyAyLjQuIEhpc3RvZ3JhbSBDaGFydAoKSGlzdG9ncmFtIGlzIGEgcGxvdCB1c2VkIG9ubHkgZm9yICoqUXVhbnRpdGF0aXZlIERhdGEqKiwgaXQgaXMgYmFzZWQgb24gYSBmcmVxdWVuY3kgdGFibGVzIGluIGNsYXNzZXMuIFRoZSAqUiogZnVuY3Rpb24gaXMgY2FsbGVkICpoaXN0KiBhbmQgdGhlIGlucHV0IGlzIGEgc2ltcGxlIGRpc3RyaWJ1dGlvbiBvZiBhIHF1YW50aXRhdGl2ZSB2YXJpYWJsZS4KCmBgYHtyfQpoaXN0KFgkU2VwYWwuTGVuZ3RoKQpgYGAKCmBgYHtyfQpoaXN0KFgkU2VwYWwuV2lkdGgsIG1haW4gPSAiSGlzdG9ncmFtIG9mIFNlcGFsIFdpZHRoIiwgeGxhYiA9ICJDbGFzc2VzIiwgeWxhYiA9ICJBYnNvbHV0ZSBGcmVxdWVuY3kiLCBjb2wgPSAibGlnaHRncmVlbiIsIGJvcmRlciA9ICJibHVlIikKYGBgCgojIyBbIDIuNC4gQk9OVVMgXQoKaGUgaGlzdG9ncmFtIGNhbiBiZSB1c2VkIG9ubHkgZm9yICoqcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyoqLiAKCmBgYHtyfQpoaXN0KFgkU2VwYWwuV2lkdGgsIG1haW4gPSAiSGlzdG9ncmFtIG9mIHRoZSBTZXBhbCBXaWR0aCIsIHhsYWIgPSAiQ2xhc3NlcyIsCiAgICAgeWxhYiA9ICJBYnNvbHV0ZSBGcmVxdWVuY3kiLCBjb2wgPSAiZ3JlZW4iLCBib3JkZXIgPSAicmVkIiwgYnJlYWtzID0gMTApCgpgYGAKCkluIGNhc2Ugb2YgZXF1YWxseSBzcGFjZWQgKHNhbWUgc2l6ZSkgY2xhc3NlcyB3ZSBjYW4gcmVwb3J0IG9uIHRoZSAqWSogYXhpcyB0aGUgQWJzb2x1dGUgRnJlcXVlbmN5IG9yIHJlbGF0aXZlIGZyZXF1ZW5jeS4gSW4gY2FzZSBvZiBjbGFzc2VzIHdpdGggZGlmZmVyZW50IHNpemVzIHdlIGhhdmUgdG8gcmVwb3J0IG9uICpZKiBheGlzIHRoZSAqZGVuc2l0eSBvZiBmcmVxdWVuY3kqLiBUaGUgZm9ybXVsYSBpcyB0aGUgZm9sbG93aW5nOiAkZF9pID0gbl9pL2hfaSQsIHdoZXJlICRuX2kkIGlzIHRoZSBhYnNvbHV0ZSBmcmVxdWVuY3kgYW5kICRoX2kkIGlzIHRoZSBzaXplIG9mIHRoZSBjbGFzcy4KCiMgMy4gQ29ycmVsYXRpb24gQW5hbHlzaXMKCiMjIDMuMS4gQ29ycmVsYXRpb24gUGxvdAoKYGBge3J9CnBsb3QoWCRTZXBhbC5MZW5ndGgsIFgkU2VwYWwuV2lkdGgsIG1haW4gPSAiQ29ycmVsYXRpb24gUGxvdCIsIHhsYWIgPSAiU2VwYWwgTGVuZ3RoIiwgeWxhYiA9ICJTZXBhbCBXaWR0aCIpCmBgYAoKIyMgWyAzLjEuIEJPTlVTIF0KCmBgYHtyfQpwbG90KFgkUGV0YWwuTGVuZ3RoLCBYJFBldGFsLldpZHRoLCBtYWluID0gIkNvcnJlbGF0aW9uIFBsb3QiLAogICAgIHhsYWIgPSAiUGV0YWwgTGVuZ2h0IiwgeWxhYiA9ICJQZXRhbCBXaWR0aCIsIGNvbCA9ICJibHVlIiwKICAgICBwY2ggPSAxKQpgYGAKClBsb3RzIHdpdGggSVJJUwoKYGBge3J9CnBsb3QoWCRTZXBhbC5MZW5ndGgsIFgkU2VwYWwuV2lkdGgsIG1haW4gPSAiKDEtMikgUGxvdCB3aXRoIElSSVMiLCAKICAgICB4bGFiID0gIlNlcGFsIExlbmdodCIsIHlsYWIgPSAiU2VwYWwgV2lkdGgiLCBjb2wgPSAiYmx1ZSIpCnBsb3QoWCRQZXRhbC5MZW5ndGgsIFgkUGV0YWwuV2lkdGgsIG1haW4gPSAiKDItMikgUGxvdCB3aXRoIElSSVMiLCAKICAgICB4bGFiID0gIlBldGFsIExlbmdodCIsIHlsYWIgPSAiUGV0YWwgV2lkdGgiLCBjb2wgPSAicmVkIikKYGBgCgojIyAzLjIuIFBhaXIgUGxvdAoKYGBge3J9CnBhaXJzKFhbICwxOjRdKQpgYGAKClRoZSBwbG90cyBiZWxvdyB0aGUgbWFpbiBkaWFnb25hbCBhcmUgdGhlIHNhbWUgb2YgdGhlIHBsb3QgYWJvdmUgdGhlIG1haW4gZGlhZ29uYWwuIFRoZSByZWFzb24gaXMgYmVjYXVzZSB0aGUgcGxvdCBhbmQgdGhlIGNvcnJlbGF0aW9uIGluZGV4IGFyZSBzeW1tZXRyaWMuCgpgYGB7cn0KciA8LSBjb3IoWFsgLDE6Ml0pCnIgPC0gcm91bmQociwgMykKcgpjb3IoWCRTZXBhbC5MZW5ndGgsIFgkU2VwYWwuV2lkdGgpCgpgYGAKClRoZSByYW5nZSBvZiBjb3JyZWxhdGlvbiBpbmRleCBpczogKi0xIDw9IHIgPD0gMSoKVGhlIGludGVycHJldGF0aW9uIG9mIHRoZSAqQ29ycmVsYXRpb24gSW5kZXgqIGNhbGxlZCAqKnIqKiBpcyBmb2xsb3dpbmc6CgotIDAuMDAgPCB8cnwgPD0gMC4yNSAqTG93IENvcnJlbGF0aW9uKgotIDAuMjUgPCB8cnwgPD0gMC41MCAqTWVkaXVtLUxvdyBDb3JyZWxhdGlvbioKLSAwLjUwIDwgfHJ8IDw9IDAuNzUgKk1lZGl1bS1IaWdoIENvcnJlbGF0aW9uKgotIDAuNzUgPCB8cnwgPD0gMS4wMCAqSGlnaCBDb3JyZWxhdGlvbioKLSAwICpObyBDb3JyZWxhdGlvbioKLSAxICpQZXJmZWN0IENvcnJlbGF0aW9uKgoKVGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gKlNlcGFsIExlbmd0aCogYW5kICpTZXBhbCBXaWR0aCogaXMgLTAuMTE4IGFuZCBpdCBpcyBhIGxvdyBuZWdhdGl2ZSBjb3JyZWxhdGlvbi4KCiMgNC4gUGxvdHMgd2l0aCBHR1BMT1QgUGFja2FnZQoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKR0dQTE9UUyBoYXMgMyBtYWluIGFyZ3VtZW50czoKCi0gVGhlIGZpcnN0IGFyZ3VtZW50IGlzIHRoZSBkYXRhOiAqZ2dwbG90KGRhdGEgPSBYKSouIEl0IGNyZWF0ZXMgYW4gZW1wdHkgZnJhbWUuCi0gVGhlIHNlY29uZCBhcmd1bWVudCBpcyB0aGUgZ2VvbWV0cnkgKHR5cGUgb2YgcGxvdCk6ICpnZW9tXyouIEl0IGFkZHMgYSBsYXllciB3aXRoIHRoZSB0eXBlIG9mIHBsb3Qgd2Ugd2FudCB0byBzaG93LgotIFRoZSB0aGlyZCBhcmd1bWVudCBpcyB0aGUgYWVzdGhldGljLCB0byBzZWxlY3QgdGhlIHZhcmlhYmxlcyBhbmQgdGhlIHByb3BlcnRpZXM6ICptYXBwaW5nID0gYWVzKCkqCgpgYGB7cn0KIyBHR1BMT1QgKGV4YW1wbGUgbm8gMSkKZ2dwbG90KGRhdGEgPSBYWyAsMToyXSkKIyBHR1BMT1QgKGV4YW1wbGUgbm8gMi4xKQpnZ3Bsb3QoZGF0YSA9IFhbICwxOjJdKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKFgkU2VwYWwuTGVuZ3RoLCBYJFNlcGFsLldpZHRoKSkKIyBHR1BMT1QgKGV4YW1wbGUgbm8gMi4yKQpnZ3Bsb3QoZGF0YSA9IFhbICwxOjJdKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKFNlcGFsLkxlbmd0aCwgU2VwYWwuV2lkdGgpKQojIEdHUExPVCAoZXhhbXBsZSBubyAyLjIpCmdncGxvdChkYXRhID0gWCkgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyhTZXBhbC5MZW5ndGgsIFNlcGFsLldpZHRoKSkKIyBHR1BMT1QgKGV4YW1wbGUgbm8gMykKZ2dwbG90KGRhdGEgPSBYKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKFNlcGFsLkxlbmd0aCwgU2VwYWwuV2lkdGgpKSArCiAgZ2d0aXRsZSgiU2NhdHRlciBQbG90IikgKyB4bGFiKCJTZXBhbCBMZW5ndGgiKSArIHlsYWIoIlNlcGFsIFdpZHRoIikKYGBgCgojIyA0LjEuIENvcnJlbGF0aW9uIFBsb3QgKFNjYXR0ZXIgUGxvdCkgd2l0aCBjb2xvcnMKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFgpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoU2VwYWwuTGVuZ3RoLCBTZXBhbC5XaWR0aCwgY29sb3IgPSBTcGVjaWVzKSkKYGBgCgojIyBbIDQuMS4gQk9OVVMgXQoKKipTVEFOREFSRCBURU1QTEFURSBJUzoqKgogIGdncGxvdChkYXRhID0gPERBVEE+KSArIAogIDxHRU9NX0ZVTkNUSU9OPihtYXBwaW5nID0gYWVzKDxNQVBQSU5HUz4pKQoKYGBge3J9CiMgRmlyc3QgRXhhbXBsZQpnZ3Bsb3QoZGF0YSA9IFgpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKFBldGFsLkxlbmd0aCwgUGV0YWwuV2lkdGgsIGNvbG9yID0gU3BlY2llcykpICsKICBnZ3RpdGxlKCJQZXRhbCBMZW5naHQgYW5kIFdpZHRoIikgKwogIHhsYWIoIlBldGFsIExlbmdodCIpICsgeWxhYigiUGV0YWwgV2lkdGgiKQojIFNlY29uZCBFeGFtcGxlCmdncGxvdChkYXRhID0gWCwgbWFwcGluZyA9IGFlcyhQZXRhbC5XaWR0aCwgUGV0YWwuTGVuZ3RoKSkgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3IgPSBTcGVjaWVzKSkgKwogIGdndGl0bGUoIlBldGFsIFdpZHRoIGFuZCBMZW5naHQiKSArIAogIHhsYWIoIlBldGFsIFdpZHRoIikgKyB5bGFiKCJQZXRhbCBMZW5naHQiKQpgYGAKCiMjIDQuMi4gQm94IFBsb3QKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFgpICsKICBnZW9tX2JveHBsb3QobWFwcGluZyA9IGFlcyhTZXBhbC5XaWR0aCksIGNvbG9yID0gImJsdWUiLCBvdXRsaWVyLmNvbG91ciA9ICJyZWQiLCBvdXRsaWVyLnNoYXBlID0gOCwgb3V0bGllci5zaXplID0gMykgKwogIGdndGl0bGUoIkJveCBQbG90IGZvciBTZXBhbCBMZW5naHQiKQpgYGAKCkJveCBQbG90IHRha2luZyBpbnRvIGFjY291bnQgdGhlIDMgdHlwZXMgb2YgZmxvd2VycwoKYGBge3J9CmdncGxvdChkYXRhID0gWCkgKwogIGdlb21fYm94cGxvdChtYXBwaW5nID0gYWVzKFNwZWNpZXMsIFNlcGFsLldpZHRoKSwgb3V0bGllci5jb2xvciA9ICJyZWQiLCBvdXRsaWVyLnNoYXBlID0gOCkKYGBgCgpHR1BMT1QgZnVuY3Rpb24gYXMgb2JqZWN0CgpgYGB7cn0KcCA8LSBnZ3Bsb3QoZGF0YSA9IFgpICsKICBnZW9tX2JveHBsb3QobWFwcGluZyA9IGFlcyhTcGVjaWVzLCBTZXBhbC5XaWR0aCwgZmlsbCA9IFNwZWNpZXMpKQpwCnAgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgojIyA0LjMuIEJhciBQbG90CgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBYKSArIAogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoU3BlY2llcykpICsgCiAgZ2d0aXRsZSgiQmFyIFBsb3Qgd2l0aCBHR1BMT1QiKSArIAogIHlsYWIoIkFic29sdXRlIEZyZXF1ZW5jeSIpCmBgYAoKIyA1LiBVc2UgdGhlIG1wZyBkYXRhIChtcGcgRnVlbCBlY29ub215IGRhdGEgZnJvbSAxOTk5IHRvIDIwMDggZm9yIDM4IHBvcHVsYXIgbW9kZWwgb2YgY2FycykKCkEgZGF0YSBmcmFtZSB3aXRoIDIzNCByb3dzIGFuZCAxMSB2YXJpYWJsZXM6CgotICptYW51ZmFjdHVyZXIqIGJyYW5kIG5hbWUKLSAqbW9kZWwqIG1vZGVsIG5hbWUKLSAqZGlzcGwqIGVuZ2luZSBkaXNwbGFjZW1lbnQsIGluIGxpdHJlcyAocG93ZXIgb2YgdGhlIGVuZ2luZSkKLSAqeWVhciogeWVhciBvZiBtYW51ZmFjdHVyZQotICpjeWwqIG51bWJlciBvZiBjeWxpbmRlcnMKLSAqdHJhbnMqIHR5cGUgb2YgdHJhbnNtaXNzaW9uCi0gKmRydiogdGhlIHR5cGUgb2YgZHJpdmUgdHJhaW4sIHdoZXJlIGYgPSBmcm9udC13aGVlbCBkcml2ZSwgciA9IHJlYXIgd2hlZWwgZHJpdmUsIDQgPSA0d2QKLSAqY3R5KiBjaXR5IG1pbGVzIHBlciBnYWxsb24gKGttIHBlciBsaXRlciBpbiB0b3duKQotICpod3kqIGhpZ2h3YXkgbWlsZXMgcGVyIGdhbGxvbiAoa20gcGVyIGxpdGVyIGluIGhpZ2h3YXkpCi0gKmZsKiBmdWVsIHR5cGUKLSAqY2xhc3MqICJ0eXBlIiBvZiBjYXIKCmBgYHtyfQpZIDwtIG1wZwpgYGAKCmBgYHtyfQpzdW1tYXJ5KFkpCmhlYWQoWSkKYGBgCgojIyA1LjEuIEJhciBDaGFydAoKYGBge3J9CnRhYmxlKFkkY3lsKQpgYGAKCmBgYHtyfQojIGZpcnN0IGV4YW1wbGU6IGZhY3RvcihjeWwpIGFzIGEgY29sb3IgKCB2ZXJ0aWNhbCBiYXIgY2hhcnQgKQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKGN5bCwgZmlsbCA9IGZhY3RvcihjeWwpKSkKIyBzZWNvbmQgZXhhbXBsZTogY2xhc3MgYXMgYSBjb2xvciAoIHZlcnRpY2FsIGJhciBjaGFydCApCmdncGxvdChkYXRhID0gWSkgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoY3lsLCBmaWxsID0gY2xhc3MpKQojIHRoaXJkIGV4YW1wbGU6IGNsYXNzIGluc3RlYWQgY3lsICggdmVydGljYWwgYmFyIGNoYXJ0ICkKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyhjeWwsIGZpbGwgPSBjbGFzcykpCiMgZm91cnRoIGV4YW1wbGU6IGNsYXNzIGluc3RlYWQgY3lsICggaG9yaXpvbnRhbCBiYXIgY2hhcnQgKQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKGN5bCwgZmlsbCA9IGNsYXNzKSkgKyBjb29yZF9mbGlwKCkKIyBmaWZ0aCBleGFtcGxlOiBjbGFzcyBpbnN0ZWFkIGN5bCAoIGhvcml6b250YWwgYmFyIGNoYXJ0ICYgbGVnZW5kIGF0IHRoZSBib3R0b20gKQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKGN5bCwgZmlsbCA9IGNsYXNzKSkgKyBjb29yZF9mbGlwKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgojIyA1LjIuIEhpc3RvZ3JhbQoKYGBge3J9CiMgZXhhbXBsZSBubyAxLjEKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyhjdHkpKQojIGV4YW1wbGUgbm8gMS4yCmdncGxvdChkYXRhID0gWSkgKwogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoY3R5LCBjb2xvdXIgPSBjbGFzcykpCiMgZXhhbXBsZSBubyAxLjMKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyhjdHksIGZpbGwgPSBjbGFzcykpCiMgZXhhbXBsZSBubyAxLjQKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyhjdHksIGZpbGwgPSAicmVkIikpCiMgZXhhbXBsZSBubyAxLjUKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyhjdHksIGZpbGwgPSBmYWN0b3IoY3R5KSkpCiMgZXhhbXBsZSAyCmdncGxvdChkYXRhID0gWSkgKwogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoaHd5KSkKYGBgCgojIyA1LjMuIEZhY2V0IFdyYXAgd2l0aCAxIGdydXAgdmFyaWFibGUgWypdCgpXaXRoIEZhY2V0IFdyYXAgbGF5ZXIgKG9wdGlvbikgd2UgY2FuIGNyZWF0ZSBzdWItcGxvdHMgYmFzZWQgb24gYSBjYXRlZ29yaWNhbCB2YXJpYWJsZS4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSkpICsKICBmYWNldF93cmFwKH5kcnYpCmBgYAoKIyMgNS40LiBGYWNldCBXcmFwIHdpdGggMiBncnVwIHZhcmlhYmxlcyBbKl0KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSkpICsKICBmYWNldF93cmFwKGRydiB+IGNsYXNzKQpgYGAKCiMjIDUuNS4gU21vb3RpbmcgUGxvdCBbKl0KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKGRpc3BsLCBod3kpKQpgYGAKCiMjIyA1LjUuMS4gU21vb3RpbmcgUGxvdCB3aXRoICJkaWZmZXJlbnQgdHlwZSBvZiBsaW5lIiBbKl0KCmBgYHtyfQojIEZpcnN0IEV4YW1wbGUKZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyhkaXNwbCwgaHd5LCBsaW5ldHlwZSA9IGNsYXNzKSkKIyBTZWNvbmQgRXhhbXBsZQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKGRpc3BsLCBod3ksIGxpbmV0eXBlID0gZHJ2KSkKYGBgCgojIyMgNS41LjIuIFNtb290aW5nIFBsb3Qgd2l0aCAiRmFjZXQgV3JhcCIgWypdCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyhkaXNwbCwgaHd5KSkgKwogIGZhY2V0X3dyYXAofiBkcnYpCmBgYAoKIyMjIDUuNS4zLiBTbW9vdGluZyBQbG90IHdpdGggImNvbG9yIiBbKl0KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKGRpc3BsLCBod3ksIGNvbG9yID0gZHJ2KSkKYGBgCgojIyMgNS41LjQuIFNtb290aW5nIFBsb3Qgd2l0aCAiZ3JvdXAiIFsqXQoKYGBge3J9CmdncGxvdChkYXRhID0gWSkgKwogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSwgZ3JvdXAgPSBkcnYpKQpgYGAKCiMjIyA1LjUuNS4gU21vb3RpbmcgUGxvdCBjb21iaW5pbmcgZGlmZmVyZW50IGxheWVycyBbKl0KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSwgY29sb3IgPSBkcnYpKSArCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyhkaXNwbCwgaHd5LCBjb2xvciA9IGRydikpCmBgYAoKIyA2LiBSZWdyZXNzaW9uIE1vZGVsIFsqXQoKSW4gcmVncmVzc2lvbiBtb2RlbCB3ZSBuZWVkIHRvIGRlZmluZSB0aGUgKmRlcGVuZGVudCogYW5kICppbmRlcGVuZGVudCogdmFyaWFibGVzLiBJbiBvdXIgY2FzZSB0aGUgbW9kZWwgaXMgZGVmaW5lIGFzIGZvbGxvdzoKCi0gKlkoRGVwZW5kZW50L091dGNvbWUgVmFyaWFibGUpKiA9ICoqaHd5KiouIFRoZSB2YXJpYWJsZSBkZWZpbmVzIHRoZSBudW1iZXIgb2YgbWlsZXMgKGttKSBwZXIgR2FsbG9uIChsaXRlcikgb24gdGhlIGhpZ2h3YXkuCi0gKlgoSW5kZXBlbmRlbnQvSW5wdXQgVmFyaWFibGUpKiA9ICoqZGlzcGwqKi4gVGhlIHZhcmlhYmxlIGRlZmluZXMgdGhlIHBvd2VyIG9mIHRoZSBlbmdpbmUgKGhvcnNlIHBvd2VyKS4KCkluIHRoZSBmaXJzdCBwbGFjZSB3ZSBuZWVkIHRvIGNyZWF0ZSBhIHNjYXR0ZXIgcGxvdCAoY29ycmVsYXRpb24gcGxvdCkuCgojIyA2LjEuIFJlZ3Jlc3Npb24gTW9kZWw6IFBsb3QgWypdCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBZKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGRpc3BsLCBod3kpKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0sIG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSkpCmBgYAoKIyMgNi4yLiBSZWdyZXNzaW9uIE1vZGVsOiBEaWZmZXJlbnQgUGxvdCBwZXIgZWFjaCBncm91cCBbKl0KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IFkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoZGlzcGwsIGh3eSwgY29sb3IgID0gZHJ2KSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLCBtYXBwaW5nID0gYWVzKGRpc3BsLCBod3ksIGNvbG9yID0gZHJ2KSkKCmBgYAoKIyMgNi4zLiBSZWdyZXNzaW9uIE1vZGVsOiBQYXJhbWV0ZXJzIEVzdGltYXRpb24gWypdCgpgYGB7cn0KcmVzLnJlZyA8LSBsbShod3kgfiBkaXNwbCwgZGF0YSA9IFkpCnN1bW1hcnkocmVzLnJlZykKYGBgCgoKCg==